home *** CD-ROM | disk | FTP | other *** search
- /* This file is part of 'minixfs' Copyright 1991,1992,1993,1994 S.N.Henson */
-
- #include "minixfs.h"
- #include "proto.h"
- #include "global.h"
-
- FILESYS minix_filesys = {
- (FILESYS *) 0,
- FS_CASESENSITIVE | FS_LONGPATH,
- m_root, m_lookup, m_creat, m_getdev,
- m_getxattr, m_chattr, m_chown,
- m_chmode, m_mkdir,
- m_rmdir, m_remove, m_getname,
- m_rename, m_opendir, m_readdir,
- m_rewinddir, m_closedir,
- m_pathconf, m_dfree,
- m_wlabel, m_rlabel,
- m_symlink, m_readlink,
- m_hardlink, m_fscntl, m_dskchng,
- m_release,m_dupcookie
- };
-
- extern DEVDRV minix_dev;
-
- static restore_dev=-1;
-
- /*
- * the kernel calls this when it detects a disk change. Note the mnt_flags
- * flag MNT_CHANGE signals that the drive is being changed to force relogging
- * of it's root directory and it should not be completely changed.
- */
-
- /*
- * Hack alert: disk changes on mounted filesystems are ungracefully handled.
- * Basically, if it isn't the first forced change then they are ignored. See
- * comment (3) in #if does_not_work_yet for reason. This isn't any great loss
- * because changing mounted filesystems is very naughty (causing various Unix
- * variants to panic, in more senses than one. If Unix doesn't handle it why
- * should I? ). Actually since changes, by necessity force the mounted
- * structure to be destroyed, there isn't much we can gracefully do.
- */
-
- long m_dskchng(d)
- int d;
- {
- FILEPTR *f, **last;
- super_info *psblk;
- char ignore;
- psblk=super_ptr[d];
-
- TRACE("Disk Change drive %c",d+'A');
-
- if(psblk && psblk!=DFS)
- {
- ignore = psblk->mnt_flags & MNT_CHANGE;
- /* If mounted then (for now) ignore changes */
- if(!ignore && psblk->mnt_inode) return 0;
- }
- else ignore=0;
-
- if(psblk && psblk!=DFS && !ignore)
- {
- Kfree(psblk->ibitmap);
-
- #if does_not_work_yet
-
- /* Need to do three things:
- * 1. Make sure all children are no longer mounted.
- * 2. Make sure filesystem is no longer searched in lookups
- * of parent device.
- * 3. (sigh) Force media change of all descendents without
- * disturbing mounted structure, so MiNT will reread the
- * root dirs properly.
- */
-
- if(psblk->mnt_inode)
- /* Umount this filesystem */
- {
- super_info **ublk,*tsblk;
- /* Unlink from list on parent device */
- for(ublk=&super_ptr[psblk->mnt_dev]->mnt_first;*ublk;
- ublk=&(*ublk)->mnt_next)
- if(*ublk==psblk)
- {
- *ublk=psblk->mnt_next;
- break;
- }
- /* Umount all children */
- for(tsblk=psblk->mnt_first;tsblk;tsblk=tsblk->mnt_next)
- tsblk->mnt_inode=0;
- }
- #endif
- Kfree(psblk);
- }
- if(!ignore) super_ptr[d]=0;
-
- /* this may affect the m_getname cache, too */
- if (lpath && (d == lroot.dev || d == ldir.dev)) {
- Kfree(lpath);
- lpath = 0;
- }
-
- /* Since the disk has changed always invalidate cache */
- m_invalidate(d);
-
- /* Free any memory associated to file pointers of this drive. */
- last = &firstptr;
- for (f = *last; f != 0; f = *last)
- {
- if (f->fc.dev == d)
- {
- f_cache *fch = (f_cache *) f->devinfo;
- /* The lock structure is shared between the fileptr's.
- Make sure that it is freed only once. */
- if (!f->next || f->next->fc.dev != d
- || f->next->fc.index != f->fc.index)
- {
- LOCK *lck, *nextlck;
- nextlck = *fch->lfirst;
- while ((lck = nextlck) != 0)
- {
- nextlck = lck->next;
- Kfree (lck);
- }
- Kfree (fch->lfirst);
- }
- Kfree (fch);
- /* Remove this fileptr from the list. */
- *last = f->next;
- f->next = 0;
- }
- else
- last = &f->next;
- }
-
- if(!ignore) minix_sanity(d);
-
- return 1;
- }
-
- /*
- * Note: in the first round of initialisations, we assume that floppy
- * drives (A and B) don't belong to us; but in a later disk change,
- * they may very well be ours, so we remember that. This is means that a
- * minix disk inserted into a drive will be unrecognisable at boot up and
- * a forced disk change is needed. However for MiNT 1.05 (and presumably
- * later) drives are initialised on first access so this isn't needed.
- */
-
- long m_root(dev,dir)
- int dev;
- fcookie *dir;
- {
- int ret;
- static first_init = 2;
- extern FILESYS dummy_filesys;
- super_info **psblk;
-
- psblk = super_ptr+dev;
-
- ret=0;
-
- if( (kernel->maj_version==0 ) ||
- (kernel->maj_version==1 && kernel->min_version < 5 ) ) {
- /* the first 2 checks (on A: and B:) we fail automatically */
- if (first_init ) {
- --first_init;
- return -1;
- }
- }
-
- /* If not present, see if it's valid */
- if( *psblk || ( dev >= 0 && (ret=minix_sanity(dev)) ) ) {
- if(ret ==-1 || *psblk==DFS ) dir->fs = &dummy_filesys;
- else
- {
- dir->fs=&minix_filesys;
- /* Aux field tells original device */
- dir->aux= dev | AUX_DRV ;
- dir->index=ROOT_INODE;
- /* If mounted trace back to root filesystem */
- while((*psblk)->mnt_inode)
- {
- dev=(*psblk)->mnt_dev;
- psblk=super_ptr+dev;
- }
- }
- dir->dev=dev;
- return 0;
-
- }
- return -1;
- }
-
- long m_lookup(dir,name,entry)
- fcookie *dir;
- char *name;
- fcookie *entry;
- {
-
- if(!*name)
- {
- *entry=*dir;
- entry->aux=0;
- return 0;
- }
-
- if(dir->index==ROOT_INODE && !strcmp(name,".."))
- {
- *entry=*dir;
- /* If mounted treat as a lookup from mount point */
- if( cross_mount(entry) ) return EMOUNT;
- DEBUG("m_lookup: crossing mount point");
- entry->index = search_dir(name,entry->index,entry->dev,FIND);
- if(entry->index < 0 ) return entry->index;
- entry->aux=0;
- return 0;
- }
-
- entry->index=search_dir(name,dir->index,dir->dev,FIND);
- entry->dev=dir->dev;
- if(entry->index < 0 ) return entry->index ;
- entry->aux=0;
- entry->fs=&minix_filesys;
- if( check_mount(entry) ) DEBUG("Crossed mount point");
- return 0;
- }
-
- long m_creat(dir,name,mode,attr,entry)
- fcookie *dir;
- char *name;
- unsigned mode;
- int attr;
- fcookie *entry;
- {
- long pos;
- d_inode ripnew;
- unshort newfile;
- char *ext;
-
- /* Create dir entry */
- if((pos=search_dir(name,dir->index,dir->dev,ADD))<0)
- {
- return pos;
- }
-
- /* Get new inode */
- if(!(newfile=alloc_inode(dir->dev)))
- {
- DEBUG("m_getdev: no free inodes");
- return EWRITF;
- }
- /* Set up inode */
- bzero(&ripnew,sizeof(d_inode));
-
- /* If creating a file with approriate extensions
- * automatically give it execute permissions.
- */
- if(do_trans(AEXEC_TOS,dir->dev) && ( ext=strrchr(name,'.') ) )
- {
- ext++;
- if(
- /* Insert your favourite extensions here */
- !( Stricmp(ext,"TTP") && Stricmp(ext,"PRG")
- && Stricmp(ext,"APP") && Stricmp(ext,"TOS")
- && Stricmp(ext,"ACC") && Stricmp(ext, "GTP")))
- mode |= 0111;
- }
- ripnew.i_mode= I_REGULAR | mode;
- ripnew.i_uid=Getuid();
- ripnew.i_gid=Getgid();
- ripnew.i_nlinks=1;
-
- ripnew.i_mtime=Unixtime(Timestamp(), Datestamp());
- ripnew.i_atime=ripnew.i_mtime;
- ripnew.i_ctime=ripnew.i_mtime;
-
- write_inode(newfile,&ripnew,dir->dev);
- l_write(dir->index,pos,2L,&newfile,dir->dev);
-
- if(cache_mode) l_sync();
-
- entry->fs = dir->fs;
- entry->dev = dir->dev;
- entry->index=newfile;
- entry->aux=0;
- return 0;
- }
-
- DEVDRV * m_getdev(file,special)
- fcookie *file;
- long *special;
- {
- return(&minix_dev);
- }
-
- long m_getxattr(file,xattr)
- fcookie *file;
- XATTR *xattr;
- {
- d_inode rip;
- long time_tmp;
- super_info *psblk;
- psblk=super_ptr[file->dev];
- read_inode(file->index,&rip,file->dev);
- /* Minix and gcc use different values for FIFO's */
- if((rip.i_mode & I_TYPE) == I_NAMED_PIPE)
- xattr->mode = S_IFIFO | (rip.i_mode & ALL_MODES);
- else xattr->mode=rip.i_mode;
-
- /* We could potentially have trouble with symlinks too */
- #if I_SYMLINK != S_IFLNK
- if( (rip.i_mode & I_TYPE) == I_SYMLINK)
- xattr->mode = S_IFLNK | (rip.i_mode & ALL_MODES);
- #endif
-
- /* Fake attr field a bit , to keep TOS happy */
- if(IS_DIR(rip))xattr->attr=FA_DIR;
- else xattr->attr=(rip.i_mode & 0222) ? 0 : FA_RDONLY;
-
- xattr->index=file->index;
- xattr->dev=file->dev;
-
- /* Char and block special files need major/minor device nos filled in */
- if(IM_SPEC(rip.i_mode)) xattr->rdev=rip.i_zone[0];
- else xattr->rdev=0;
-
- xattr->nlink=rip.i_nlinks;
- xattr->uid=rip.i_uid;
- xattr->gid=rip.i_gid;
- xattr->size=rip.i_size;
- xattr->blksize = BLOCK_SIZE;
- /* Note: the nblocks calculation is accurate only if the file is
- * contiguous. It usually will be, and if it's not, it shouldn't
- * matter ('du' will return values that are slightly too high)
- */
- xattr->nblocks = (xattr->size + (BLOCK_SIZE-1)) / BLOCK_SIZE;
- if (xattr->nblocks >= psblk->dzpi)
- xattr->nblocks++; /* correct for the indirection block */
- if (xattr->nblocks > psblk->ndbl) {
- xattr->nblocks++; /* correct for double indirection block */
- xattr->nblocks += ((xattr->nblocks-(psblk->ndbl+2))/psblk->zpind);
- /* and single indirection blocks */
- }
-
- time_tmp=Dostime(_corr(rip.i_mtime));
- xattr->mtime=time_tmp >> 16;
- xattr->mdate=time_tmp & (0xffff);
- time_tmp=Dostime(_corr(rip.i_atime));
- xattr->atime=time_tmp >> 16;
- xattr->adate=time_tmp & (0xffff);
- time_tmp=Dostime(_corr(rip.i_ctime));
- xattr->ctime=time_tmp >> 16;
- xattr->cdate=time_tmp & (0xffff);
-
- xattr->reserved2=0;
- xattr->reserved3[0]=0;
- xattr->reserved3[1]=0;
-
- return 0;
- }
-
- long m_chown(file, uid , gid)
- fcookie *file;
- int uid,gid;
- {
-
- d_inode rip;
- read_inode(file->index,&rip,file->dev);
- if(uid!=-1)rip.i_uid=uid;
- if(gid!=-1)rip.i_gid=gid;
- rip.i_ctime=Unixtime(Timestamp(),Datestamp());
- write_inode(file->index,&rip,file->dev);
- if(cache_mode) l_sync();
- return 0;
- }
-
- long m_chmode(file, mode)
- fcookie *file;
- unsigned mode;
- {
- d_inode rip;
- super_info *psblk=super_ptr[file->dev];
-
- read_inode(file->index,&rip,file->dev);
-
- rip.i_mode=(rip.i_mode & I_TYPE)|(mode & ALL_MODES);
- if(psblk->version)rip.i_ctime=Unixtime(Timestamp(),Datestamp());
- write_inode(file->index,&rip,file->dev);
- if(cache_mode) l_sync();
- return 0;
- }
-
-
- long m_mkdir(dir,name,mode)
- fcookie *dir;
- char *name;
- unsigned mode;
- {
- unshort newdir;
- d_inode rip,ripnew;
- long pos;
- int incr;
- dir_struct blank[MAX_INCREMENT*2];
- incr=super_ptr[dir->dev]->increment;
- if((pos=search_dir(name,dir->index,dir->dev,ADD))<0)return pos;
- read_inode(dir->index,&rip,dir->dev);
- if(rip.i_nlinks>=MINIX_MAX_LINK)return EACCDN;
- /* Get new inode */
- if(!(newdir=alloc_inode(dir->dev)))return EACCDN;
-
- /* Set up inode */
- bzero(&ripnew,sizeof(d_inode));
- ripnew.i_mode=I_DIRECTORY | (mode & 0777);
- ripnew.i_uid=Getuid();
- ripnew.i_gid=Getgid();
- ripnew.i_nlinks=2;
- ripnew.i_mtime=Unixtime(Timestamp(), Datestamp());
- ripnew.i_ctime=ripnew.i_mtime;
- ripnew.i_atime=ripnew.i_mtime;
- write_inode(newdir,&ripnew,dir->dev);
-
- /* Set up new directory */
- strcpy(blank[0].d_name,".");
- blank[0].d_inum=newdir;
- strcpy(blank[incr].d_name,"..");
- blank[incr].d_inum=dir->index;
- if(l_write((unsigned)newdir,-1L,(long)(DIR_ENTRY_SIZE*2*incr),
- blank,dir->dev)!=(incr*DIR_ENTRY_SIZE*2) )
- {
- ripnew.i_mode=0;
- ripnew.i_nlinks=0;
- write_inode(newdir,&ripnew,dir->dev);
- free_inode(newdir,dir->dev);
- if(cache_mode) l_sync();
- return EACCDN;
- }
- rip.i_nlinks++;
- write_inode(dir->index,&rip,dir->dev);
- l_write(dir->index,pos,2L,&newdir,dir->dev);
-
- if(cache_mode) l_sync();
-
- return(0);
- }
-
- long m_rmdir(dir,name)
- fcookie *dir;
- char *name;
- {
- long chunk,left;
- long inum;
- int i,incr;
- super_info *psblk;
- d_inode rip,rip2;
- if((inum=search_dir(name,dir->index,dir->dev,FIND))<0)return inum;
-
- /* Is anything mounted on this dir ? */
- for(psblk=super_ptr[dir->dev]->mnt_first;psblk;psblk=psblk->mnt_next)
- if(psblk->mnt_inode==inum)
- {
- DEBUG("m_rmdir: can't delete mount point");
- return EACCDN;
- }
-
- read_inode(inum,&rip,dir->dev);
- read_inode(dir->index,&rip2,dir->dev);
- if(!IS_DIR(rip))return EFILNF;
- incr=super_ptr[dir->dev]->increment;
- /* Check if dir is actually empty */
- for(chunk=0;(left=next_zone(&rip,chunk,&temp,dir->dev)/DIR_ENTRY_SIZE);
- chunk++)
- {
- for(i=0;i<left;i+=incr)
- if (temp.bdir[i].d_inum
- && (temp.bdir[i].d_name[0] != '.'
- || temp.bdir[i].d_name[1] != 0)
- && (temp.bdir[i].d_name[0] != '.'
- || temp.bdir[i].d_name[1] != '.'
- || temp.bdir[i].d_name[2] != 0))
- return EACCDN ;
- }
- if(!inode_busy(inum,dir->dev,1))
- {
- trunc_inode(&rip,dir->dev,0L,0);
- rip.i_mode=0;
- free_inode(inum,dir->dev);
- }
- rip.i_nlinks=0;
- write_inode(inum,&rip,dir->dev);
- read_inode(dir->index,&rip,dir->dev);
- rip.i_mtime=Unixtime(Timestamp(), Datestamp());
- rip.i_nlinks--;
- write_inode(dir->index,&rip,dir->dev);
- search_dir(name,dir->index,dir->dev,KILL);
-
- if( lpath && (ldir.dev==dir->dev) && (ldir.index==inum) )
- {
- Kfree(lpath);
- lpath=0;
- }
-
- if(cache_mode) l_sync();
-
- return(0);
- }
-
- /* Unix-like unlink ... handle regulars, symlinks and specials.
- *
- */
-
- long m_remove(dir,name)
- fcookie *dir;
- char *name;
- {
- long inum,ret;
- char spec; /* Special file */
- d_inode rip;
- inum=search_dir(name,dir->index,dir->dev,FIND);
- if(inum<0) return inum;
- read_inode(inum,&rip,dir->dev);
- if(!IS_REG(rip) && !IS_SYM(rip) )
- {
- if(!IM_SPEC(rip.i_mode)) return EACCDN;
- spec=1;
- }
- else spec=0;
- if((ret=search_dir(name,dir->index,dir->dev,KILL))<0) return ret;
- if(--rip.i_nlinks==0)
- {
- if(spec || !inode_busy(inum,dir->dev,1)) /* Is inode busy ? */
- {
- if(!spec) trunc_inode(&rip,dir->dev,0L,0);
- rip.i_mode=0;
- free_inode(inum,dir->dev);
- }
- }
- write_inode(inum,&rip,dir->dev);
-
- if(cache_mode) l_sync();
-
- return(0);
- }
-
- /* This function is inefficient, it uses the standard sys V method of
- * finding out the pathname of the cwd : for each part of the path, search
- * the parent for a link with the same inode number as '..' , append this to the
- * path until we get to root dir, then reverse order of dirs. This way no
- * temporary buffers are allocated which could overflow or kmalloc to fail ...
- */
-
- /* In fact its so inefficient a mini-cache remembers the last call info */
-
- long m_getname(root,dir,pathname,length)
- fcookie *root,*dir;
- char *pathname;
- short length;
- {
- long inum,pinum;
- unsigned dev;
- int chunk;
- long left;
- int incr;
- short plength;
- super_info *psblk;
- psblk=super_ptr[dir->dev];
-
- if(no_length) length=PATH_MAX;
-
- if(lpath && lroot.dev==root->dev &&
- lroot.index==root->index && ldir.dev==dir->dev &&
- ldir.index==dir->index)
- {
- TRACE("m_getname: cache hit");
- if(length <= llength) return ENAMETOOLONG;
- strcpy(pathname,lpath);
- return 0;
- }
-
- *pathname=0;
-
- if( dir->dev==root->dev && dir->index==root->index) return 0;
-
- incr=psblk->increment;
- inum=dir->index;
- dev=dir->dev;
- plength=0;
- if(inum==ROOT_INODE && psblk->mnt_inode)
- {
- dev=psblk->mnt_dev;
- inum=psblk->mnt_inode;
- psblk=super_ptr[dev];
- }
-
- while( inum!=root->index && inum!= ROOT_INODE )
- {
- d_inode rip;
- cache *tmp;
- pinum=search_dir("..",inum,dev,FIND);
- /* Parent inum */
-
- if(pinum < 0) /* If this happens we're in trouble */
- {
- ALERT("No .. in inode %d , drive %c",inum,dir->dev+'A');
- return pinum;
- }
- read_inode(pinum,&rip,dev);
- for(chunk=0;
- (left=cnext_zone(&rip,chunk,&tmp,dev)/DIR_ENTRY_SIZE) &&
- inum!=pinum ;chunk++)
- {
- char tname[MNAME_MAX+1];
- int i;
- for(i=0;i<left && inum!=pinum ;i+=incr)
- if(tmp->buffer->bdir[i].d_inum==inum)
- {
- strncpy(tname,tmp->buffer->bdir[i].d_name,MMAX_FNAME(incr));
- tname[MMAX_FNAME(incr)]=0;
- strrev(tname);
- plength+=strlen(tname)+1;
- if(length <= plength) return ENAMETOOLONG;
- strcat(pathname,tname);
- strcat(pathname,"\\");
- inum=pinum;
- }
- }
- if(left==0 && inum!=pinum) {
- ALERT("m_getname inode %d orphaned or bad ..",inum);
- return EINTRN;
- }
- /* Cross mount point if possible */
- if(inum==ROOT_INODE && psblk->mnt_inode)
- {
- dev=psblk->mnt_dev;
- inum=psblk->mnt_inode;
- psblk=super_ptr[dev];
- }
- }
- if(inum==ROOT_INODE && root->index!=ROOT_INODE)
- {
- DEBUG("m_getname: Hmmmm root is not a parent of dir");
- return EINTRN;
- }
- strrev(pathname);
- if(lpath)Kfree(lpath);
- if( (lpath=Kmalloc(strlen(pathname)+1)) )
- {
- strcpy(lpath,pathname);
- llength=plength;
- }
-
- lroot=*root;
- ldir=*dir;
- return 0;
- }
-
-
- long m_opendir(dirh,flag)
- DIR *dirh;
- int flag;
- {
- dirh->index=0;
- return 0;
- }
-
- long m_readdir(dirh,name,namelen,fc)
- DIR *dirh;
- char *name;
- int namelen;
- fcookie *fc;
- {
- d_inode rip;
- cache *tmp;
- unsigned entry,chunk;
- super_info *psblk;
- long limit;
- int flag,incr;
- psblk=super_ptr[dirh->fc.dev];
- if(dirh->flags) flag=do_trans(DIR_TOS,dirh->fc.dev);
- else flag=0;
- if(!dirh->fc.index)return EACCDN;
- entry=dirh->index % NR_DIR_ENTRIES;
- chunk=dirh->index / NR_DIR_ENTRIES;
- read_inode(dirh->fc.index,&rip,dirh->fc.dev);
- incr=psblk->increment;
-
- while( (limit=cnext_zone(&rip,chunk,&tmp,dirh->fc.dev)/DIR_ENTRY_SIZE) )
- {
- while( entry < limit)
- {
- dir_struct *try=&tmp->buffer->bdir[entry];
- entry+=incr;
- if(try->d_inum)
- {
- char *tmpnam;
- tmpnam=tosify(try->d_name,flag,MMAX_FNAME(incr));
-
- if (dirh->flags==0)
- {
- namelen -= sizeof(long);
- if (namelen <= 0) return ERANGE;
- *((long *)name) = (long)try->d_inum;
- name += sizeof(long);
- }
-
- strncpy(name,tmpnam,namelen);
- dirh->index=entry+chunk*NR_DIR_ENTRIES;
- /* set up a file cookie for this entry */
- fc->dev = dirh->fc.dev;
- fc->aux = 0;
- fc->index = (long)try->d_inum;
- fc->fs = &minix_filesys;
- if(strlen(tmpnam) >= namelen)
- return ENAMETOOLONG;
- /* If turbo mode set atime here: we'll only
- * change the cache here so it wont cause
- * lots of I/O
- */
- if( cache_mode==TURBO
- && super_ptr[dirh->fc.dev]->version
- && dirh->fc.dev > 1 )
- set_atime(&dirh->fc);
- return 0;
- }
- }
- if(entry!=NR_DIR_ENTRIES)return ENMFIL;
- else entry=0;
- chunk++;
- }
- return ENMFIL;
- }
-
- long m_rewinddir(dirh)
- DIR *dirh;
- {
- dirh->index=0;
- return 0;
- }
-
- long m_closedir(dirh)
- DIR *dirh;
- {
-
- /* Access time is set here if we aren't in TURBO cache mode. Otherwise we
- * would be sync'ing on every dir read which would be far too slow. See note
- * in set_atime().
- */
-
- if( cache_mode!=TURBO && super_ptr[dirh->fc.dev]->version &&
- dirh->fc.dev > 1 )
- {
- set_atime(&dirh->fc);
- l_sync();
- }
-
- dirh->fc.index=0;
- return 0;
- }
-
- /* Set the atime of a V2 inode for filesystems. There is a snag here: if the
- * disk is changed then this is likely not to be written out before the whole
- * cache is invalidated. So we set the status to '3' which means that it is
- * not alerted if this is dirty when invalidated (hardly the end of the world
- * if the atime is slightly wrong!)
- */
- void set_atime(fc)
- fcookie *fc;
- {
- d_inode *rip;
- int *status;
- rip=get_inode2(fc->index,fc->dev,&status,NOGUESS);
- rip->i_atime=Unixtime(Timestamp(),Datestamp());
- if(*status!=2) *status=3;
- }
-
-
- long m_rlabel(dir,name,namelen)
- fcookie *dir;
- char *name;
- int namelen;
- {
- return EFILNF;
- }
-
- long m_wlabel(dir,name)
- fcookie *dir;
- char *name;
- {
- return EACCDN;
- }
-
- long m_dfree(dir,buffer)
- fcookie *dir;
- long *buffer;
- {
- super_info *psblk ;
- psblk = super_ptr[dir->dev];
- buffer[1] = psblk->sblk.s_zones-psblk->sblk.s_firstdatazn;
- buffer[0] = buffer[1] - count_bits(psblk->zbitmap,buffer[1]+1)+1;
- buffer[2]=512L;
- buffer[3]=2L;
- return(0);
- }
-
- long m_fscntl(dir,name,cmd,arg)
- fcookie *dir;
- char *name;
- int cmd;
- long arg;
- {
- FILEPTR *f;
- mfs_info *inf;
- super_info *psblk;
- long inum;
- int uid,gid,id;
- d_inode rip;
- extern long init_addr;
-
- uid = Geteuid();
- gid = Getegid();
-
- switch(cmd)
- {
- case MFS_VERIFY:
- *((long *)arg)=MFS_MAGIC;
- return 0;
-
- /* Sync the filesystem */
- case MFS_SYNC:
- TRACE("Done l_sync()");
- l_sync();
- return 0;
-
- /* Invalidate all cache entries for a given drive */
- case MFS_CINVALID:
- if(uid) return EACCDN;
- m_invalidate(dir->dev);
- return 0;
-
- /* Invalidate all fileptrs for a given drive */
- case MFS_FINVALID:
- if(uid) return EACCDN;
- id=Getpid();
- for(f=firstptr;f;f=f->next)if(f->fc.dev==dir->dev)m_close(f,id);
- return 0;
-
- case MFS_INFO:
- psblk=super_ptr[dir->dev];
- inf=(mfs_info *)arg;
- inf->total_zones=psblk->sblk.s_zones-psblk->sblk.s_firstdatazn;
- inf->total_inodes=psblk->sblk.s_ninodes;
- inf->version=psblk->version+1;
- inf->increment=psblk->increment;
- inf->free_inodes=inf->total_inodes-
- count_bits(psblk->ibitmap,inf->total_inodes+1)+1;
- inf->free_zones=inf->total_zones-count_bits(psblk->zbitmap,inf->total_zones+1)+1;
- return 0;
-
- case MFS_IMODE:
- if(uid) return EACCDN;
- inum=search_dir(name,dir->index,dir->dev,FIND);
- if(inum < 0 ) return inum;
- read_inode(inum,&rip,dir->dev);
- rip.i_mode=arg;
- write_inode(inum,&rip,dir->dev);
- return 0;
-
- case MFS_GTRANS:
- *((long *) arg)=fs_mode[dir->dev];
- return 0;
-
- case MFS_STRANS:
- if(uid) return EACCDN;
- fs_mode[dir->dev]=*((long *)arg);
- return 0;
-
- case MFS_PHYS:
- *((struct phys_part *)arg)=ppart[dir->dev];
- return 0;
-
- case MFS_IADDR:
- *((long *)arg)=(long)&init_addr;
- return 0;
-
- case MFS_UPDATE:
- if(cache_mode!=TURBO ) return -1;
- switch(arg)
- {
- case 0:
- return update_suspend;
-
- case 1:
- TRACE("Minixfs: update suspended");
- update_suspend=1;
- return 0;
-
- case 2:
- TRACE("Minixfs: update restarted");
- update_suspend=0;
- return 0;
-
- case 3:
- if(Addroottimeout) return -1;
- return update_pid;
-
- default:
- return EINVFN;
- }
-
- /* Mounting and umounting.
- * This basically involves cookie translation when crossing the mount point.
- * However this presents an interesting problem. Suppose E:\usr has D: mounted
- * on it. If we are in directory E:\usr\ we are in the root directory of D:.
- * If we do a cd \ then we get sent back to the root cookie directory of D:,
- * which we want to be E:. The only way to change the root cookie at present is
- * to force a disk change, this is no problem.
- * The fun starts when we want to umount D:. Changing D: will have no effect
- * because the root cookie of D: is now on E: and since E: hasn't changed the
- * root cookie on D: wont change either. If we change E: then we will get the
- * root cookie of D: changed but we also change E: as well.
- * The only way out is to fiddle the aux field of the root cookie so it shows
- * the original device. The cookie from m_root is copied with the dup_cookie
- * function, if we kludge this at umount time to read the aux field and copy
- * the original device the root cookies should be set back. This relies very
- * heavily on the structure of filesys.c in MiNT, but it's better than nothing.
- * Repeat after me: KLUDGE, KLUDGE, KLUDGE, KLUDGE, KLUDGE!!!
- */
-
- case MFS_MOUNT:
- {
- char tpath[]="A:";
- fcookie fc;
- unsigned dev;
- super_info *mptr;
- if(uid) return EACCDN;
- /* Lookup the entry */
- if( (inum=m_lookup(dir,name,&fc)) ) return inum;
- read_inode(fc.index,&rip,fc.dev);
- /* Must be a directory */
- if(!IS_DIR(rip))
- {
- DEBUG("MFS_MOUNT: not a directory!");
- return EACCDN;
- }
-
- if(fc.index==ROOT_INODE)
- {
- DEBUG("MFS_MOUNT: can't mount on root!");
- return EACCDN;
- }
- if(!arg) return EINVFN;
- dev = ( ( mfs_mount *) arg)->dev ;
-
- if(fc.dev==dev)
- {
- DEBUG("MFS_MOUNT: can't mount on self!");
- return EACCDN;
- }
-
- tpath[0]='A'+dev;
-
- /* Sync filesystem (and force access if unrecognised) */
-
- d_cntl(MFS_SYNC,tpath,0l);
-
- psblk=super_ptr[dev];
-
- if(!psblk || psblk==DFS)
- {
- DEBUG("MFS_MOUNT: not a Minixfs filesystem!");
- return EACCDN;
- }
-
- if(psblk->mnt_inode)
- {
- DEBUG("MFS_MOUNT: filesystem already mounted!");
- return EACCDN;
- }
-
- if(psblk->mnt_first)
- {
- DEBUG("MFS_MOUNT: filesystem has others mounted!");
- return EACCDN;
- }
-
- for(mptr=super_ptr[fc.dev]->mnt_first;
- mptr;mptr=mptr->mnt_next)
- {
- if( mptr->mnt_inode==fc.index )
- {
- DEBUG("MFS_MOUNT: inode already mounted on!");
- return EACCDN;
- }
- }
-
- mptr=super_ptr[fc.dev];
-
- psblk->mnt_next=mptr->mnt_first;
- mptr->mnt_first=psblk;
-
- psblk->mnt_dev=fc.dev;
- psblk->mnt_inode=fc.index;
-
- psblk->mnt_flags |= MNT_CHANGE;
-
- /* Force change */
- d_lock(1,dev);
- d_lock(0,dev);
-
- d_cntl(MFS_SYNC,tpath,0l);
-
- psblk->mnt_flags &= ~MNT_CHANGE;
-
- return 0;
- }
-
- case MFS_UMOUNT:
- {
- fcookie fc;
- super_info **pptr,*pdev;
- char tpath[]="A:";
-
- if(uid) return EACCDN;
- /* Lookup path */
- if( ( inum=m_lookup(dir,name,&fc) ) ) return inum;
-
- psblk=super_ptr[fc.dev];
-
- /* Can't have other devices mounted */
- if(psblk->mnt_first)
- {
- DEBUG("MFS_UMOUNT: device busy");
- return EACCDN;
- }
-
- if(!psblk->mnt_inode)
- {
- DEBUG("MFS_UMOUNT: not mounted");
- return EACCDN;
- }
-
- /* Unlink from parent filesystem list */
- for(pptr=&super_ptr[psblk->mnt_dev]->mnt_first;*pptr;
- pptr=&(*pptr)->mnt_next )
- {
- if(*pptr==psblk)
- {
- *pptr = psblk->mnt_next;
- break;
- }
- }
-
- pdev=psblk;
-
- /* Find root device */
- while(pdev->mnt_inode) pdev = super_ptr[pdev->mnt_dev];
-
- psblk->mnt_inode=0;
-
- pdev->mnt_flags |= MNT_CHANGE;
-
- /* Make dupcookie restore dev fields */
- restore_dev = psblk->dev;
-
- /* Change root device */
- d_lock(1,pdev->dev);
- d_lock(0,pdev->dev);
-
- tpath[0] = 'A'+pdev->dev;
- d_cntl(MFS_SYNC,tpath,0l);
-
- restore_dev = -1;
-
- pdev->mnt_flags &= ~MNT_CHANGE;
-
- return 0;
-
- }
-
- case FUTIME:
- case FTRUNCATE:
- {
- fcookie fc;
- read_inode(dir->index,&rip,dir->dev);
- /* Have we got 'x' access for current dir ? */
- if (check_mode(uid,gid,&rip,S_IXUSR))
- return EACCDN;
- /* Lookup the entry */
- if( (inum=m_lookup(dir,name,&fc)) ) return inum;
- read_inode(fc.index,&rip,fc.dev);
- if(cmd==FUTIME)
- {
- short *timeptr = (short *) arg;
- /* The owner or super-user can always touch,
- others only if timeptr == 0 and write
- permission. */
- if (uid && uid != rip.i_uid
- && (timeptr
- || check_mode (uid, gid, &rip, S_IWUSR)))
- return EACCDN;
-
- rip.i_ctime = Unixtime(Timestamp (), Datestamp ());
- if(timeptr)
- {
- rip.i_atime = Unixtime(timeptr[0], timeptr[1]);
- rip.i_mtime = Unixtime(timeptr[2], timeptr[3]);
- }
- else rip.i_atime = rip.i_mtime = rip.i_ctime;
- write_inode (fc.index, &rip, fc.dev);
- if (cache_mode != TURBO) l_sync();
- return 0;
- }
-
- if(!IS_REG(rip)) return EACCDN;
- /* Need write access as well */
- if (check_mode(uid, gid, &rip, S_IWUSR))
- return EACCDN;
- itruncate(fc.index,fc.dev,*((long *)arg));
- if (cache_mode != TURBO) l_sync ();
- return 0;
- }
-
- case MFS_LOPEN:
- {
- long fcount;
- openf_list *flist = (openf_list *) arg;
- fcount=0;
- inum=0;
- for(f=firstptr;f;f=f->next)
- {
- /* If same file or wrong device, skip */
- if( f->fc.dev!=dir->dev || f->fc.index==inum) continue;
- inum=f->fc.index;
- flist->flist[fcount++]=inum;
- if(fcount==flist->limit) return ERANGE;
- }
- flist->flist[fcount]=0;
- }
- return 0;
-
- case MFS_MKNOD:
- {
- long pos;
- unsigned inm,mode;
-
- if(uid) return EACCDN;
- mode = arg & 0xffff;
-
- /* Char and block specials only at present */
- if(!IM_SPEC(mode))return ERANGE;
-
- /* Create new name */
- pos=search_dir(name,dir->index,dir->dev,ADD);
- if(pos < 0) return pos;
- inm=alloc_inode(dir->dev);
- if(!inm) return EWRITF;
-
- bzero(&rip,sizeof(d_inode));
-
- rip.i_mode = mode;
- rip.i_uid = uid;
- rip.i_gid = gid;
- rip.i_nlinks = 1;
-
- rip.i_mtime=Unixtime(Timestamp(), Datestamp());
- rip.i_atime=rip.i_mtime;
- rip.i_ctime=rip.i_mtime;
- rip.i_zone[0]= arg >> 16;
-
- write_inode(inm,&rip,dir->dev);
- l_write(dir->index,pos,2L,&inm,dir->dev);
- if(cache_mode) l_sync();
-
- }
- return 0;
-
- default:
- return EINVFN;
- }
- }
-
- /* m_rename, move a file or directory. Directories need special attention
- * because if /usr/foo is moved to /usr/foo/bar then the filesystem will be
- * damaged by making the /usr/foo directory inaccessible. The sanity checking
- * performed is very simple but should cover all cases: Start at the parent
- * of the destination , check if this is the source inode , if not then
- * move back to '..' and check again , repeatedly check until the root inode
- * is reached , if the source is ever seen on the way back to the root then
- * the rename is invalid , otherwise it should be OK.
- */
-
- long m_rename(olddir,oldname,newdir,newname)
- fcookie *olddir;
- char *oldname;
- fcookie *newdir;
- char *newname;
- {
- long finode,ret;
- d_inode rip;
- long pos;
- char dirmove,dirren;
- dirmove=0;
- dirren=0;
- /* Check cross drives */
- if(olddir->dev!=newdir->dev)return EXDEV;
-
- /* Check new doesn't exist and path is otherwise valid */
- finode=search_dir(newname,newdir->index,newdir->dev,FIND);
- if(finode>0) return EACCDN;
- if(finode!=EFILNF) return finode;
-
- /* Check old path OK */
- if((finode=search_dir(oldname,olddir->index,olddir->dev,FIND))<0)
- return finode;
-
- read_inode(finode,&rip,olddir->dev);
-
- /* Sanity check movement of directories */
- if(IS_DIR(rip))
- {
- dirren=1;
- if(olddir->index!=newdir->index)
- {
- #ifdef MFS_NMOVE_DIR
- return EACCDN;
- #else
- d_inode riptemp;
- ret=is_parent(newdir->index,finode,olddir->dev);
- if(ret < 0) return ret;
- if(ret) return EACCDN;
- read_inode(newdir->index,&riptemp,newdir->dev);
- if(riptemp.i_nlinks==MINIX_MAX_LINK) return EACCDN;
- TRACE("minixfs: valid directory move");
- dirmove=1;
- #endif
- }
- }
-
- /* Check the m_getname cache is not invalidated by this move ....
- if no dir move, invalidate if the ldir is the name being changed ,
- if we move dir's then if the olddir is a parent of ldir, invalidate */
-
- if (lpath && ldir.dev == olddir->dev
- && (ldir.index == finode
- || (dirmove && is_parent (ldir.index, finode, olddir->dev) > 0)))
- {
- Kfree (lpath);
- lpath=0;
- }
-
- /* Create new entry */
- if((pos=search_dir(newname,newdir->index,newdir->dev,ADD))<0) return pos;
- /* Delete old path */
- if((finode=search_dir(oldname,olddir->index,olddir->dev,KILL))<0)
- return finode;
- {
- unshort ino = finode;
- l_write (newdir->index, pos, 2L, &ino, newdir->dev);
- }
-
- /* When moving directories, fixup things like '..' and nlinks of old and
- * new dirs
- */
-
- if(dirmove)
- {
- pos=search_dir("..",finode,newdir->dev,POS);
- if(pos<0)
- {
- ALERT("m_rename: no .. in inode %ld",finode);
- return EACCDN;
- }
- if(pos!=DIR_ENTRY_SIZE*super_ptr[newdir->dev]->increment)
- ALERT("m_rename: Unexpected .. position in inode %ld",finode);
- {
- unshort ino = newdir->index;
- l_write (finode, pos, 2L, &ino, newdir->dev);
- }
- read_inode(olddir->index,&rip,olddir->dev);
- rip.i_nlinks--;
- write_inode(olddir->index,&rip,olddir->dev);
- read_inode(newdir->index,&rip,newdir->dev);
- rip.i_nlinks++;
- write_inode(newdir->index,&rip,newdir->dev);
- }
-
- if(cache_mode) l_sync();
-
- /* Check the m_getname cache is not invalidated by this move ....
- * if no dir alter, invalidate if the ldir is the name being changed ,
- * if we alter dir's then if the moved dir is a parent of ldir, invalidate.
- */
-
- if (lpath && ldir.dev == olddir->dev
- && (ldir.index == finode
- || (dirren && is_parent (ldir.index, finode, olddir->dev) > 0)))
- {
- Kfree (lpath);
- lpath=0;
- }
-
- return 0;
- }
-
- /* Minix hard-link, you can't make a hardlink to a directory ... it causes
- * too much trouble, use symbolic links instead.
- */
-
- long m_hardlink(fromdir,fromname,todir,toname)
- fcookie *fromdir;
- char *fromname;
- fcookie *todir;
- char *toname;
- {
- long finode;
- d_inode rip;
- long pos;
-
- /* Check cross drives */
- if(fromdir->dev!=todir->dev)return EXDEV;
-
- /* Check new doesn't exist and path is otherwise valid */
- finode=search_dir(toname,todir->index,todir->dev,FIND);
- if(finode>0) return EACCDN;
- if(finode!=EFILNF) return finode;
-
- /* Check old path OK */
- if((finode=search_dir(fromname,fromdir->index,fromdir->dev,FIND))<0)
- return finode;
-
- read_inode(finode,&rip,fromdir->dev);
- if( (!IS_REG(rip) && !IM_SPEC(rip.i_mode))
- || (rip.i_nlinks >=MINIX_MAX_LINK) ) return EACCDN;
-
- /* Create new entry */
- if((pos=search_dir(toname,todir->index,todir->dev,ADD))<0) return pos;
- {
- unshort ino = finode;
- l_write (todir->index, pos, 2L, &ino, todir->dev);
- }
- rip.i_nlinks++;
- rip.i_ctime=Unixtime(Timestamp(),Datestamp());
- write_inode(finode,&rip,fromdir->dev);
-
- if(cache_mode) l_sync();
-
- return 0;
- }
-
- /* Symbolic links ... basically similar to a regular file with one zone */
-
- long m_symlink(dir,name,to)
- fcookie *dir;
- char *name;
- char *to;
- {
- d_inode rip;
- long pos;
- unshort newinode;
-
- if(!*to)
- {
- DEBUG("m_symlink: invalid null filename");
- return EACCDN;
- }
-
- if(strlen(to)>=SYMLINK_NAME_MAX)
- {
- DEBUG("minixfs: Symbolic link name too long");
- return ERANGE;
- }
-
- if((pos=search_dir(name,dir->index,dir->dev,ADD))<0) return pos;
-
- if(!(newinode=alloc_inode(dir->dev)))
- {
- DEBUG("minixfs: symlink drive %c,no free inodes",dir->dev+'A');
- return EACCDN;
- }
-
-
- bzero(&rip,sizeof(d_inode));
- rip.i_mode=I_SYMLINK | 0777;
- rip.i_size=strlen(to)+1;
- rip.i_uid=Getuid();
- rip.i_gid=Getgid();
- rip.i_mtime=Unixtime(Timestamp(),Datestamp());
- rip.i_ctime=rip.i_mtime;
- rip.i_atime=rip.i_mtime;
- rip.i_nlinks=1;
-
- if(!(rip.i_zone[0]=alloc_zone(dir->dev)))
- {
- free_inode(newinode,dir->dev);
- DEBUG("minixfs: symlink drive %c no free zones",dir->dev+'A');
- return EACCDN;
- }
- btos_cpy((char *)&temp,to);
- write_zone(rip.i_zone[0],&temp,dir->dev,&syscache);
- write_inode(newinode,&rip,dir->dev);
- l_write(dir->index,pos,2L,&newinode,dir->dev);
-
- if(cache_mode) l_sync();
-
- return 0;
- }
-
- long m_readlink(file,buf,len)
- fcookie *file;
- char *buf;
- int len;
- {
- long inum = file->index;
- d_inode rip;
-
- read_inode(inum,&rip,file->dev);
- if( (rip.i_mode & I_TYPE)!=I_SYMLINK)
- {
- DEBUG("minixfs: attempted readlink on non-symlink");
- return EACCDN;
- }
- read_zone(rip.i_zone[0],&temp,file->dev,&syscache);
- if(stob_ncpy(buf, (char *) &temp,len))
- {
- DEBUG("m_readlink: name too long");
- return ERANGE;
- }
- TRACE("m_readlink returned %s",buf);
-
- return 0;
- }
-
- /* the only settable attribute is FA_RDONLY; if the bit is set,
- * the mode is changed so that no write permission exists
- */
- long m_chattr(file,attr)
- fcookie *file;
- int attr;
- {
- long inum = file->index;
- int drive = file->dev;
- d_inode rip;
-
- if ( (attr & FA_RDONLY) ) {
- read_inode(inum,&rip,drive);
- rip.i_mode &= ~(0222); /* turn off write permission */
- rip.i_ctime=Unixtime(Timestamp(),Datestamp());
- write_inode(inum,&rip,drive);
- if(cache_mode) l_sync();
- } else if (attr == 0) {
- read_inode(inum,&rip,drive);
- if ( (rip.i_mode & 0222) == 0 ) {
- rip.i_mode |= ( (rip.i_mode&0444) >> 1 );
- /* turn write permission back on */
- rip.i_ctime=Unixtime(Timestamp(),Datestamp());
- write_inode(inum,&rip,drive);
- if(cache_mode) l_sync();
- }
- }
- return 0;
- }
-
- long m_pathconf(dir,which)
- fcookie *dir;
- int which;
- {
- switch(which) {
- case -1:
- return DP_MAXREQ;
- case DP_IOPEN:
- return UNLIMITED;
- case DP_MAXLINKS:
- return MINIX_MAX_LINK;
- case DP_PATHMAX:
- return UNLIMITED; /* At last ! */
- case DP_NAMEMAX:
- return MMAX_FNAME(super_ptr[dir->dev]->increment);
- case DP_ATOMIC:
- return BLOCK_SIZE; /* we can write at least a block atomically */
- case DP_TRUNC:
- return DP_AUTOTRUNC;
- case DP_CASE:
- return DP_CASESENS; /* Well sort of ... */
- default:
- return EINVFN;
- }
- }
-
- long m_release(fc)
- fcookie *fc;
- {
- return 0;
- }
-
- long m_dupcookie(dest,src)
- fcookie *dest,*src;
- {
- unsigned tmpaux;
- tmpaux=dest->aux;
- *dest=*src;
- if(restore_dev!=-1 &&
- (tmpaux & (AUX_DEV|AUX_DRV))== restore_dev|AUX_DRV )
- dest->dev = tmpaux & AUX_DEV;
-
- return 0;
- }
-